/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package war;

/**
 *
 * @author Rosario
 */





import com.google.gdata.client.GoogleService;
import com.google.gdata.data.acl.AclEntry;
import com.google.gdata.data.acl.AclFeed;
import com.google.gdata.data.acl.AclNamespace;
import com.google.gdata.data.acl.AclRole;
import com.google.gdata.data.acl.AclScope;
import com.google.gdata.data.calendar.CalendarAclRole;


import com.google.gdata.client.Query;
import com.google.gdata.client.calendar.CalendarQuery;

import com.google.gdata.data.DateTime;
import com.google.gdata.data.Link;

import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;

import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;

import com.google.gdata.data.calendar.WebContent;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.data.extensions.Recurrence;
import com.google.gdata.data.extensions.Reminder;
import com.google.gdata.data.extensions.Reminder.Method;
import com.google.gdata.data.extensions.When;





import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.ColorProperty;
import com.google.gdata.data.calendar.HiddenProperty;
import com.google.gdata.data.calendar.SelectedProperty;
import com.google.gdata.data.calendar.TimeZoneProperty;
import com.google.gdata.data.extensions.Where;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Classe che consente la gestione dei calendari di google
 * da parte del sito Hometeatre,
 * passati come parametri i dati per settare le credenziali
 * la classe consente di:
 * 1- Aggiungere un calendario sull'account dell'utenza(in questa fase non utilizzato)
 * 2- Aggiungere un aclFeed del calendario di HomeTeatre al calendario dell'utenza
 * 3- Aggiungere un evento sul calendario di HomeTeatre.
 * 4- Aggiungere sul calendario dell'utenza il promemoria della prenotazione, con email-promemoria 15 giorni prima dell'evento.
 */
public class CalendarFeedD {

  // The base URL for a user's calendar metafeed (needs a username appended).
  private static final String METAFEED_URL_BASE = 
      "https://www.google.com/calendar/feeds/";

  
  private static final String ACL_FEED_URL_SUFFIX = "/acl/Full";
  // The string to add to the user's metafeedUrl to access the allcalendars
  // feed.
  private static final String ALLCALENDARS_FEED_URL_SUFFIX = 
      "/allcalendars/full";

  // The string to add to the user's metafeedUrl to access the owncalendars
  // feed.
  private static final String OWNCALENDARS_FEED_URL_SUFFIX = 
      "/owncalendars/full";

  // The URL for the metafeed of the specified user.
  // (e.g. http://www.google.com/feeds/calendar/jdoe@gmail.com)
  private static URL metafeedUrl = null;

  // The URL for the allcalendars feed of the specified user.
  // (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/allcalendars/full)
  private static URL allcalendarsFeedUrl = null;

  // The URL for the owncalendars feed of the specified user.
  // (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/owncalendars/full)
  private static URL owncalendarsFeedUrl = null;
  
   // The URL for the ACL feed of the specified user's primary calendar.
  // (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/acl/full)
  private static URL aclFeedUrl = null;
  
  

  // The URL for the event feed of the specified user's primary calendar.
  // (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/private/full)
  private static URL eventFeedUrl = null;

  // The string to add to the user's metafeedUrl to access the event feed for
  // their primary calendar.
  private static final String EVENT_FEED_URL_SUFFIX = "/private/full";
  
  // The HEX representation of red, blue and green
  private static final String RED = "#A32929";
  private static final String BLUE = "#2952A3";
  private static final String GREEN = "#0D7813";

  
  public CalendarFeedD() {
  }

 
  private static void printUserCalendars(CalendarService service, URL feedUrl)
      throws IOException, ServiceException {

    // Send the request and receive the response:
    CalendarFeed resultFeed = service.getFeed(feedUrl, CalendarFeed.class);

    // Print the title of each calendar
    for (int i = 0; i < resultFeed.getEntries().size(); i++) {
      CalendarEntry entry = resultFeed.getEntries().get(i);
     
    }
  }

  /**
   * Crea un calendario secondario attraverso un CalendarService autenticato
   */
  private static CalendarEntry createCalendar(CalendarService service)
      throws IOException, ServiceException {
    

    // Create the calendar
    CalendarEntry calendar = new CalendarEntry();
    calendar.setHidden(HiddenProperty.FALSE);
    calendar.setColor(new ColorProperty(BLUE));


    // Insert the calendar
    return service.insert(owncalendarsFeedUrl, calendar);
  }


  private static CalendarEntry updateCalendar(CalendarEntry calendar)
      throws IOException, ServiceException {
   

    calendar.setTitle(new PlainTextConstruct("New title"));
    calendar.setColor(new ColorProperty(GREEN));
    calendar.setSelected(SelectedProperty.TRUE);
    return calendar.update();
  }




 
  /**
   * Aggiunge un account al calendario di homeTeatre in modalità read-only
   * @param service un calendarService autenticato
   * @param userEmail la mail dell'utente con cui condividere il calendario
   * @param role la modalità di accesso
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
   */
  private static void addAccessControl(CalendarService service,
      String userEmail, AclRole role) throws ServiceException, IOException {
    AclEntry entry = new AclEntry();
    entry.setScope(new AclScope(AclScope.Type.USER, userEmail));
    entry.setRole(role);

    service.insert(aclFeedUrl, entry);
  }

  private static void updateAccessControl(CalendarService service,
      String userEmail, AclRole newRole) throws ServiceException, IOException {
    AclFeed aclFeed = service.getFeed(aclFeedUrl, AclFeed.class);

    for (AclEntry aclEntry : aclFeed.getEntries()) {
      if (userEmail.equals(aclEntry.getScope().getValue())) {
        aclEntry.setRole(newRole);
        AclEntry updatedEntry = aclEntry.update();

        System.out.println("Updated user's access control:");
        System.out.println("\tScope: Type=" + updatedEntry.getScope().getType()
            + " (" + updatedEntry.getScope().getValue() + ")");
        System.out.println("\tRole: " + updatedEntry.getRole().getValue());

        break;
      }
    }
  }

/**
   * Rimuove il controllo di accesso a un calendario
   * @param service un calendarService autenticato
   * @param userEmail la mail dell'utente da eliminare per la condivisione
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
   */  private static void deleteAccessControl(CalendarService service,
      String userEmail) throws ServiceException, IOException {
    AclFeed aclFeed = service.getFeed(aclFeedUrl, AclFeed.class);

    for (AclEntry aclEntry : aclFeed.getEntries()) {
      if (userEmail.equals(aclEntry.getScope().getValue())) {
        aclEntry.delete();
 

        break;
      }
    }
  }

  
  /**
   * Restituisce un insieme di eventi aventi.
   * Utilizzato nel caso un utente volesse eliminare la sua prenotazione,
   * o nel caso l'admin volesse eliminare un evento(non ancora implementato)
   * 
   * @param service un calendarService autenticato
   * @param query testo per la query
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
    */
  private static List<CalendarEventEntry> fullTextQuery(CalendarService service, String query)
      throws ServiceException, IOException {
    Query myQuery = new Query(eventFeedUrl);
    myQuery.setFullTextQuery(query);       
    CalendarEventFeed resultFeed = service.query(myQuery,
        CalendarEventFeed.class);
    
    List<CalendarEventEntry> eventsToDelete = 
          new ArrayList<CalendarEventEntry>();

    for (int i = 0; i < resultFeed.getEntries().size(); i++) {
            eventsToDelete.add(resultFeed.getEntries().get(i));
      
    }
    return eventsToDelete;
  }

  

  /**
   * Helper method to create either single-instance or recurring events. For
   * simplicity, some values that might normally be passed as parameters (such
   * as author name, email, etc.) are hard-coded.
   * 
  * @param service un calendarService autenticato
   * @param eventTitle titolo dell'evento da creare
   * @param eventContent testo dell'evento da creare
   * @param recurData ricorrenza dell'evento
   * @param isQuickAdd true se si tratta un un evento veloce

   * @return La nuova entry del calendario
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
   */
  private static CalendarEventEntry createEvent(CalendarService service,
      String eventTitle, String eventContent, String recurData,
      boolean isQuickAdd, WebContent wc) throws ServiceException, IOException {
    CalendarEventEntry myEntry = new CalendarEventEntry();

    myEntry.setTitle(new PlainTextConstruct(eventTitle));
    myEntry.setContent(new PlainTextConstruct(eventContent));
    myEntry.setQuickAdd(isQuickAdd);
    myEntry.setWebContent(wc);
    
    
    // If a recurrence was requested, add it. Otherwise, set the
    // time (the current date and time) and duration (30 minutes)
    // of the event.
    if (recurData == null) {
      Calendar calendar = new GregorianCalendar();
      DateTime startTime = new DateTime(calendar.getTime(), TimeZone
          .getDefault());

      calendar.add(Calendar.MINUTE, 30);
      DateTime endTime = new DateTime(calendar.getTime(), 
          TimeZone.getDefault());

      When eventTimes = new When();
      
      eventTimes.setStartTime(startTime);
      eventTimes.setEndTime(endTime);
      myEntry.addTime(eventTimes);
    } else {
      Recurrence recur = new Recurrence();
      recur.setValue(recurData);
      myEntry.setRecurrence(recur);
      
    }
    

    // Send the request and receive the response:
    return service.insert(eventFeedUrl, myEntry);
  }


  
  

  /**
   * Creates a new recurring event.
   * 
   * @param service
   * @param eventTitle Titolo dell'evento da creare
   * @param eventContent Testo dell'evento
   * @param date la data dell'evento
   * @return La nuova entry del calendario
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
   */
  private static CalendarEventEntry createRecurringEvent(
      CalendarService service, String eventTitle, String eventContent, String date)
      throws ServiceException, IOException {
    // Specify a recurring event that occurs every Tuesday from May 1,
    // 2007 through September 4, 2007. Note that we are using iCal (RFC 2445)
    // syntax; see http://www.ietf.org/rfc/rfc2445.txt for more information.
    String recurData = "DTSTART;VALUE=DATE:"+date+"\r\n"
        + "DTEND;VALUE=DATE:"+date+"\r\n";

    return createEvent(service, eventTitle, eventContent, recurData, false,
        null);
  }


  /**
   * Adds a reminder to a calendar event.
   * 
   * @param entry l'evento da aggiornare
   * @param numMinutes promemoria in giorni
   * @param methodType tipo di notifica
   * @return La entry aggiornata del calendario
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
   */
  private static CalendarEventEntry addReminder(CalendarEventEntry entry,
      int numMinutes, Method methodType) throws ServiceException, IOException {
    Reminder reminder = new Reminder();
    reminder.setDays(numMinutes);
    
    reminder.setMethod(methodType);
    entry.getReminder().add(reminder);
   
    return entry.update();
  }

  
  private static CalendarEventEntry addExtendedProperty(
      CalendarEventEntry entry) throws ServiceException, IOException {
    // Add an extended property "id" with value 1234 to the EventEntry entry.
    // We specify the complete schema URL to avoid namespace collisions with
    // other applications that use the same property name.
    ExtendedProperty property = new ExtendedProperty();
    property.setName("http://www.example.com/schemas/2005#mycal.id");
    
    property.setValue("1234");
    

    entry.addExtension(property);

    return entry.update();
  }

  /**
   * Elimina un evento utilizzando la batch request.
   * Al metodo viene passato come parametro una lista di eventi che 
   * si premurerà di rimuovere
   * @param service un oggetto calendarService autenticato.
   * @param eventsToDelete lista degi eventi da eliminare.
   * @throws ServiceException se il servizio non è disponibile
   * @throws IOException se ci sono stati errori di comunicazione col server
   */
  private static void deleteEvents(CalendarService service,
      List<CalendarEventEntry> eventsToDelete) throws ServiceException,
      IOException {

    // Add each item in eventsToDelete to the batch request.
    CalendarEventFeed batchRequest = new CalendarEventFeed();
    for (int i = 0; i < eventsToDelete.size(); i++) {
      CalendarEventEntry toDelete = eventsToDelete.get(i);
      // Modify the entry toDelete with batch ID and operation type.
      BatchUtils.setBatchId(toDelete, String.valueOf(i));
      BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE);
      batchRequest.getEntries().add(toDelete);
    }

    // Get the URL to make batch requests to
    CalendarEventFeed feed = service.getFeed(eventFeedUrl,
        CalendarEventFeed.class);
    Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
    URL batchUrl = new URL(batchLink.getHref());

    // Submit the batch request
    CalendarEventFeed batchResponse = service.batch(batchUrl, batchRequest);

    // Ensure that all the operations were successful.
   
    for (CalendarEventEntry entry : batchResponse.getEntries()) {
      BatchUtils.getBatchId(entry);
      if (!BatchUtils.isSuccess(entry)) {   
        BatchUtils.getBatchStatus(entry);
      }
    }
 
  }
  
  
  

  
  

  
  public boolean newFeed(String mail, String psw){
          try {
      metafeedUrl = new URL(METAFEED_URL_BASE + mail);
      allcalendarsFeedUrl = new URL(METAFEED_URL_BASE + mail + 
          ALLCALENDARS_FEED_URL_SUFFIX);
      owncalendarsFeedUrl = new URL(METAFEED_URL_BASE + mail + 
          OWNCALENDARS_FEED_URL_SUFFIX);
    } catch (MalformedURLException e) {
        // Bad URL          
        return false;
    }
       CalendarService service = new CalendarService("demo-CalendarFeedDemo-1");

    try {
      service.setUserCredentials(mail, psw);
    } catch (AuthenticationException e) {
      // Invalid credentials
      return false;
    }

    // Demonstrate retrieving various calendar feeds.
    try {
 
      printUserCalendars(service, metafeedUrl);
 
      printUserCalendars(service, allcalendarsFeedUrl);
 
      printUserCalendars(service, owncalendarsFeedUrl);
      
//CalendarService service CalendarEntry newCalendar CalendarEntry updatedCalendar
      // Create a new secondary calendar
      CalendarEntry newCalendar = createCalendar(service);
      newCalendar.setTitle(new PlainTextConstruct("HomeTeatreEvent"));
      CalendarEntry updatedCalendar = updateCalendar(newCalendar);
    } catch (IOException e) {
      // Communications error
     
      return false;
    } catch (ServiceException e) {
      // Server side error
     
      return false;
    }
      
          
          
    return true;

      
  }
  
 /**
  * Aggiunge il calendario il feed del calendario di HomeTeatre a un utenza
  * @param userToShar l'utente con il quale si vuole condividere il feed
  */
  public boolean addSub(String userToShare) throws ServiceException{
  
      CalendarService myService = this.setAccess(2);
          if(myService==null) return false;              
          try {
   
          if (userToShare != null) {
        
                addAccessControl(myService, userToShare, CalendarAclRole.FREEBUSY);       
                updateAccessControl(myService, userToShare, CalendarAclRole.READ);

      }

    } catch (IOException e) {
      // Communications error
         return false;
    } catch (ServiceException e) {
      // Server side error
        return false;    
    }

      
      
      
      return true;
  
  }
  
  
  /**
   * Elimina il feed di un utente
   * @param userToShare la mail dell'utente con la quale si vuole condividere gli eventi
   */
   public boolean delAcc(String userToShare) throws ServiceException{
          CalendarService myService = this.setAccess(2);
          if(myService==null) return false;
          
    
          try {
      // Demonstrate retrieving access control list feeds.
     

      if (userToShare != null) {
        
        // Remove given user's access to this calendar.
        deleteAccessControl(myService, userToShare);
      }

    } catch (IOException e) {
      // Communications error
         return false;
    } catch (ServiceException e) {
      // Server side error
        return false;    
    }

      
      
      
      return true;
  
  }
   
/**
 * Aggiunge un evento al calendario di HomeTeatre
 * @param date la data dell'evento
 * @param title il titolo dell'evento
 * @return true se tutto è andato a buon fine, false altrimenti
 */
   public boolean creaEvPrivate(String date, String title) throws ServiceException{
          CalendarService myService = this.setAccess(1);
          if(myService==null) return false;
          
    
          try {
                    
          String[] items = date.split("-");
          String eve = "";
                
          for (int i=0; i<items.length; i++) {eve=items[i]+eve;}

      createRecurringEvent(myService, title, "Servizio HomeTeatre", eve);//crea l'evento

    } catch (IOException e) {  
     return false;
    }   catch (GoogleService.InvalidCredentialsException e) {
        return false;
    }           
       
    return true;
       
   }
   
   
   
/**
 * Aggiunge un evento al calendario calendario personale di un utente gmail
 * inserisce anche l'avviso mail
 * @param userName la mail dell'utente
 * @param userPass la psw dell'utente
 * @param date la data dell'evento
 * @param title il titolo dell'evento
 * @return true se tutto è andato a buon fine, false altrimenti
 */
   public boolean creaEvUser(String userName, String userPassword, String date, String title) throws ServiceException{
          CalendarService myService = this.setAccess(1, userName,userPassword);
          if(myService==null) return false;
          
    
     try {
        myService.setUserCredentials(userName, userPassword);      
        String[] items = date.split("-");        
        String eve = "";
                
                
        for (int i=0; i<items.length; i++) {                        
            eve=items[i]+eve;              
        }  
        
       CalendarEventEntry singleEvent = createRecurringEvent(myService, title, "Avviso di prenotazione all'evento: '"+title+"'."+"\n"+"Se fosse stato ancora effettuato il pagamento, si prega di passare dai nostri sportelli."+"\n"+"Nel caso si fosse scelto di viaggiare con noi la partenza sarà alle ore 7.00 da Piazza Castello(Torino)"+"\n"+" La direzione di HomeTeatre", eve);
       singleEvent.setImmutable(true);
       
       singleEvent = addReminder(singleEvent, 15, Method.EMAIL);

       singleEvent = addExtendedProperty(singleEvent);


    } catch (IOException e) {
      // Communications error
  
     return false;
    }   catch (GoogleService.InvalidCredentialsException e) {
      // Server side error
        return false;
    }
    
       
       return true;
       
   }

   


    
  
   
 /**
 * Elimina gli eventi dell'utente
 * inserisce anche l'avviso mail
 * @param userName la mail dell'utente
 * @param userPass la psw dell'utente
 * @param date la data dell'evento
 * @param title il titolo dell'evento
 * @return true se tutto è andato a buon fine, false altrimenti
 */
   public boolean deleteUserEvent(String userName, String userPassword, String date, String title) throws ServiceException{
          CalendarService myService = this.setAccess(1, userName, userPassword);
          if(myService==null) return false;
              
          try {                    
                String[] items = date.split("-");
                String eve = "";                
                
           for (int i=0; i<items.length; i++) 
           {
             eve=items[i]+eve;
           }
                       
      List<CalendarEventEntry> eventsToDelete = fullTextQuery(myService, title);
      if(!eventsToDelete.isEmpty()){
      deleteEvents(myService, eventsToDelete);
      }
      else return false;
 


    } catch (IOException e) {
      // Communications error
  
     return false;
    }   catch (GoogleService.InvalidCredentialsException e) {
      // Server side error
        return false;
    }
    
       
       return true;
       
   }

   
 /**
 * Setta le autorizzazioni necessarie per l'accesso dell'admin
 * @return true se tutto è andato a buon fine, false altrimenti
 */
   public boolean setAccess() throws ServiceException{
          CalendarService myService = new CalendarService("exampleCo-exampleApp-1");

    // Set username and password from command-line arguments.
       String userName= "hometeatreweb@gmail.com";
       String userPassword= "servizioweb";

    // Create the necessary URL objects.
    try {
      metafeedUrl = new URL(METAFEED_URL_BASE + userName);
      eventFeedUrl = new URL(METAFEED_URL_BASE + userName
          + EVENT_FEED_URL_SUFFIX);
    } catch (MalformedURLException e) {
      // Bad URL
      
      
      return false;
    }

    try {
      myService.setUserCredentials(userName, userPassword);
      
    }catch (GoogleService.InvalidCredentialsException e) {
      // Server side error
        return false;
    }
    
       
       return true;
       
   }

   
 /**
 * Setta le autorizzazioni necessarie per l'accesso dell'admin
 * @param n il tipo di accesso che si vuole fare, aggiunta calendario, aggiunta aclfeed oppure aggiunta evento
 * @return true se tutto è andato a buon fine, false altrimenti
 */
   protected CalendarService setAccess(int n) throws ServiceException{
          CalendarService myService = new CalendarService("exampleCo-exampleApp-1");

    // Set username and password from command-line arguments.
       String userName= "hometeatreweb@gmail.com";
       String userPassword= "servizioweb";

    if(n==1){
        try {
            metafeedUrl = new URL(METAFEED_URL_BASE + userName);
            eventFeedUrl = new URL(METAFEED_URL_BASE + userName
            + EVENT_FEED_URL_SUFFIX);
            } catch (MalformedURLException e) {
      // Bad URL            
            return null;
            }
        
    }
    else if(n==2){ 
        try {
            metafeedUrl = new URL(METAFEED_URL_BASE + userName);
            aclFeedUrl = new URL(METAFEED_URL_BASE + userName + ACL_FEED_URL_SUFFIX);
            } catch (MalformedURLException e) {
        // Bad URL
            return null;
            }       
    }
    else{
        return null;
    }

    try {
      myService.setUserCredentials(userName, userPassword);
      
    }catch (GoogleService.InvalidCredentialsException e) {
      // Server side error
        return null;
    }

    // Create the necessary URL objects.
    
       
       return myService;
       
   }
   
   
 /**
 * Setta le autorizzazioni necessarie per l'accesso al calendario dell'utenza
 * @param userName mail, gmail, dell'utenza
 * @param userPassword password, gmail, dell'utenza
 * @param n il tipo di accesso che si vuole fare, aggiunta calendario, aggiunta aclfeed oppure aggiunta evento
 * @return true se tutto è andato a buon fine, false altrimenti
 */
   protected CalendarService setAccess(int n, String userName, String userPassword) throws ServiceException{
          CalendarService myService = new CalendarService("exampleCo-exampleApp-1");



    if(n==1){
        try {
            metafeedUrl = new URL(METAFEED_URL_BASE + userName);
            eventFeedUrl = new URL(METAFEED_URL_BASE + userName
            + EVENT_FEED_URL_SUFFIX);
            } catch (MalformedURLException e) {
      // Bad URL            
            return null;
            }
        
    }
    else if(n==2){ 
        try {
            metafeedUrl = new URL(METAFEED_URL_BASE + userName);
            aclFeedUrl = new URL(METAFEED_URL_BASE + userName + ACL_FEED_URL_SUFFIX);
            } catch (MalformedURLException e) {
        // Bad URL
            return null;
            }       
    }
    else{
        return null;
    }

    try {
      myService.setUserCredentials(userName, userPassword);
      
    }catch (GoogleService.InvalidCredentialsException e) {
      // Server side error
        return null;
    }

    // Create the necessary URL objects.
    
       
       return myService;
       
   }
   
    
}
